﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Management;
using System.Windows.Forms;
using System.Collections;
using System.Net;
using System.Net.NetworkInformation;

namespace RemotePC.NET
{
    class ComputerRemote
    {        
        public delegate void StatusChangedHandler(object sender);
        public static event StatusChangedHandler StatusChanged;

        private Ping pingSender;

        private CheckBox myBox;
        public CheckBox MyBox
        {
            get { return myBox; }
        }

        private string name;
        public string Name
        {
            get { return name; }
            set { name = value; }
        }

        private string path;
        public string Path
        {
            get { return path; }
            set { path = value; }
        }

        private string username;
        public string Username
        {
            get { return username; }
            set { username = value; }
        }

        private string password;
        public string Password
        {
            get { return password; }
            set { password = value; }
        }

        private int status;
        public int Status
        {
            get { return status; }
            set
            {
                status = value;
                OnStatusChanged(this);
            }
        }

        private ConnectionOptions op;
        private ManagementScope scope;

        public ComputerRemote(string strName, string strPath, string strUsername, string strPassword)
        {
            name = strName;
            path = strPath;
            username = strUsername;
            password = strPassword;
            status = 1;
            OnStatusChanged(this);
        }

        public ComputerRemote(string strName, string strPath, string strUsername, string strPassword, CheckBox cb)
        {
            name = strName;
            path = strPath;
            username = strUsername;
            password = strPassword;
            myBox = cb;
            status = 1;
            OnStatusChanged(this);
        }

        public ComputerRemote(ComputerRemote cr)
        {
            name = cr.Name;
            path = cr.Path;
            username = cr.Username;
            password = cr.Password;
            myBox = cr.MyBox;
            status = cr.Status;
        }

        public bool InitConnect()
        {            
            if (name == null || name.Equals(""))
            {
                status = -2;
                OnStatusChanged(this);
                return false;
            }
            else if (name == null || path.Equals(""))
            {
                status = -3;
                OnStatusChanged(this);
                return false;
            }
            else if (name == null || username.Equals(""))
            {
                status = -4;
                OnStatusChanged(this);
                return false;
            }
            else if (name == null || password.Equals(""))
            {
                status = -5;
                OnStatusChanged(this);
                return false;
            }
            else if (!PingIt())
            {
                return false;
            }
            else
            {
                op = new ConnectionOptions();
                op.Username = name + @"\" + username;   //连接电脑用户名
                op.Password = password;                 //连接电脑密码
                scope = new ManagementScope("\\\\" + path + "\\root\\cimv2", op);
                try
                {
                    scope.Connect();
                    //MessageBox.Show("成功连接。");
                    status = 0;
                    OnStatusChanged(this);
                }
                catch (UnauthorizedAccessException uaex)
                {
                    //MessageBox.Show(uaex.Message + "\n无权访问目标主机。");
                    status = -6;
                    OnStatusChanged(this);
                }
                catch (ManagementException mex)
                {
                    //MessageBox.Show(mex.Message + "\n无法访问本机。");
                    status = -7;
                    OnStatusChanged(this);
                }
                catch (System.Runtime.InteropServices.COMException cex)
                {
                    //MessageBox.Show(cex.Message + "\nRPC服务器问题。");
                    status = -8;
                    OnStatusChanged(this);
                }
                catch (Exception ex)
                {
                    //MessageBox.Show("出现未知异常。\n" + ex.GetType().ToString() + "\n" + ex.Message);
                    status = -1;
                    OnStatusChanged(this);
                }

                if (status < 0)
                    return false;

                return true;
            }            
        }

        private bool PingIt()
        {
            bool result = false;
            pingSender = new Ping();
            PingOptions options = new PingOptions();

            // Use the default Ttl value which is 128,
            // but change the fragmentation behavior.
            options.DontFragment = true;

            // Create a buffer of 32 bytes of data to be transmitted.
            string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
            byte[] buffer = Encoding.ASCII.GetBytes(data);
            int timeout = 120;
            try
            {
                PingReply reply = pingSender.Send(path, timeout, buffer, options);
                result = (reply.Status == IPStatus.Success);
                if (!result)
                {
                    Status = -9;
                }
            }
            catch (System.Net.NetworkInformation.PingException pex)
            {
                Status = -10;
                result = false;
            }
            catch (System.Exception e)
            {
                Status = -11;
                result = false;
            }            
            return result;
        }

        public string GetStatus()
        {
            string result;
            switch (status)
            {
                case 0:
                    result = "连接正常，您可以对此计算机进行远程控制。";
                    break;
                case 1:
                    result = "未知，请先检查。";
                    break;
                case -1:
                    result = "未知异常。";
            	    break;
                case -2:
                case -3:
                case -4:
                case -5:
                    result = "计算机信息不完整，请设置好目标计算机的IP、用户名以及密码。";
                    break;
                case -6:
                    result = "无权访问此计算机，请检查目标计算机的RPC连接是否正常（如防火墙设置）。";
                    break;
                case -7:
                    result = "无法对本机进行控制。";
                    break;
                case -8:
                    result = "RPC服务出现问题，请检查目标计算机的用户名及密码是否正确，并确认其RPC服务已启动。";
                    break;
                case -9:
                    result = "无法连接远端主机，请检查目标计算机是否处在正常运行的状态下并确保与本机连接到相同的网络上。";
                    break;
                case -10:
                    result = "DNS服务器连接异常，请检查本机网络连接。";
                    break;
                case -11:
                    result = "未知连接异常。";
                    break;
                case 8:
                    result = "检查中…";
                    break;
                default:
                    result = "未知，请先检查。";
                    break;
            }
            return result;
        }

        public bool DoCommand(string doinfo)
        {
            if (status == 0)
            {
                System.Management.ObjectQuery oq = new System.Management.ObjectQuery("SELECT * FROM Win32_OperatingSystem");
                ManagementObjectSearcher query1 = new ManagementObjectSearcher(scope, oq);
                //得到WMI控制
                ManagementObjectCollection queryCollection1 = query1.Get();
                foreach (ManagementObject mobj in queryCollection1)
                {
                    string[] str = { "" };
                    mobj.InvokeMethod(doinfo, str);
                }
                return true;
            }
            else
            {
                return false;
            }
        }

        public static bool RemoteComupter(ComputerRemote cr, string doinfo)
        {
            return cr.DoCommand(doinfo);
        }

        public static bool[] RemoteComupter(ComputerRemote[] cr, string doinfo)
        {
            int index = 0;
            int n = cr.GetLength(0);
            bool[] Results = new bool[n];
            foreach (ComputerRemote thisone in cr)
            {
                Results[index] = thisone.DoCommand(doinfo);                
                index++;
            }
            return Results;
        }

        // 下面的方法用来解决可能会出现的空引用异常。
        protected void OnStatusChanged(object sender)
        {
            if (StatusChanged != null)
            {
                StatusChanged(sender);
            }
        }
    }
}
